/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现引用池的功能
* CreateTime：2020-04-05 19:50:49
* Version：1.0
* Modify Recorder：
*************************************************/

using System;
using System.Collections.Generic;

namespace TinyToolKit
{
    public sealed class ReferenceBasePool
    {
        private readonly Queue<IReference> _references;
        private readonly Type _refType;

        private int _usingReferenceCount;//正在使用的引用数量

        public Type RefType => _refType;
        public int UnusedReferenceCount => _references.Count;
        public int UsingReferenceCount => _usingReferenceCount;

        public ReferenceBasePool(Type refType)
        {
            _references = new Queue<IReference>();
            _refType = refType;
            _usingReferenceCount = 0;
        }

        #region Public Func
        public T Acquire<T>() where T : class, IReference, new()
        {
            if (typeof(T) != _refType) return null;

            _usingReferenceCount++;
            lock (_references)
            {
                if (_references.Count > 0)
                    return _references.Dequeue() as T;
            }
            return new T();
        }

        public IReference Acquire()
        {
            _usingReferenceCount++;
            lock (_references)
            {
                if (_references.Count > 0)
                    return _references.Dequeue();
            }
            return Activator.CreateInstance(_refType) as IReference;
        }

        public void Release(IReference reference)
        {
            if (reference == null) return;
            reference.Clear();

            lock (_references)
            {
                _references.Enqueue(reference);
            }

            _usingReferenceCount--;
        }

        public void Add(int count)
        {
            lock (_references)
            {
                for (int i = 0; i < count; i++) 
                {
                    _references.Enqueue(Activator.CreateInstance(_refType) as IReference);
                }
            }
        }

        public void Remove(int count)
        {
            lock (_references)
            {
                if (count > _references.Count)
                    count = _references.Count;

                for (int i = 0; i < count; i++)
                {
                    _references.Dequeue();
                }
            }
        }

        public void RemoveAll()
        {
            lock (_references)
            {
                _references.Clear();
            }
        }
        #endregion
    }
}
